﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using DataSource;

namespace Exchange
{
    public class StockExchange
    {
        public string date;
        private BlockingCollection<Order> orderQueue;
        private Dictionary<string, Order> orderDict; //保存所有未完结的订单，没有交易
        public DateTime dt;
        public delegate void DealSendEventHandler(Deal dl);
        public DealSendEventHandler OnDealReceivedEvent;

        public StockExchange(string date)
        {
            this.date = date;
            orderQueue = new BlockingCollection<Order>();
            orderDict = new Dictionary<string, Order>();
        }


        public void OnTimePulse(DateTime dt) //由时间程序决定撮合交易
        {
            this.dt = dt; //更新时间
            foreach(var key in orderDict.Keys.ToList()) //还处于挂单状态的订单，撮合成交
            {
                if (!orderDict.ContainsKey(key))
                {
                    continue; //可能前面循环中已将orderDict更新，所以需要进行判断
                }
                Order od = orderDict[key];
                if (od.type == OrderType.Cancel)
                {
                    CancelOrder(od);
                }
                else
                {
                    Transaction(od);
                }
            }
        }

        public DateTime GetCurrentTime()
        {
            return dt;
        }

        public void SendDeal(Deal dl)
        {
            OnDealReceivedEvent(dl);
        }

        public void OnOrderReceive(Order od) //收到订单后，将订单塞入订单dict，由时间片程序去负责处理
        {
            orderDict[od.id] = od;
        }

        public void CancelOrder(Order od) //订单dict中，如果有符合该订单对应撤销命令的，从订单队列中删掉,
        {
            foreach(var key in orderDict.Keys)
            {
                Order od_cand = orderDict[key];
                if(od_cand.id == od.targetId) //找到要撤销的目标订单
                {
                    orderDict.Remove(key); //把目标订单撤掉
                    Deal dl = new Deal();
                    dl.code = od_cand.code;
                    dl.type = OrderType.Cancel;
                    dl.id = od.id; //反馈单id和接收单id一致
                    dl.side = od_cand.side;
                    dl.price = od_cand.price;
                    dl.isCanceled = true;
                    dl.volume = od_cand.volume;
                    SendDeal(dl);
                    break;
                }
            }
            orderDict.Remove(od.id); //把该撤销单也取消掉
            
        }

        public void Transaction(Order od)
        {
           Deal dl = null;
           if(od.type == OrderType.Market)
            {
                dl = MarketOrderTransaction(od);
            }
           else if(od.type == OrderType.Limit)
            {
                dl = LimitOrderTransaction(od);
            }
            SendDeal(dl);
        }

        public Deal MarketOrderTransaction(Order od)
        {
            Level2Struct ls = SimulateMarket.GetInstance().GetMarketSnapshot(od.code);
            int vol = od.volume; // 订单剩余量
            int count = 0;
            double amount = 0;
            int quotePos = 0;

            if (od.side == TradeSide.Buy)
            {
                for (int i = 0; i < ls.sell_amount.Count; i++)
                {
                    if (ls.sell_amount[i] < vol)
                    {
                        vol -= ls.sell_amount[i];
                        count += 1;
                        amount += ls.sell_amount[i] * ls.sell_px[i];
                    }
                    else
                    {
                        count += 1;
                        amount += vol * ls.sell_px[i];
                        vol = 0;
                        break;
                    }
                }
            }
            else
            {
                for (int i = 0; i < ls.buy_amount.Count; i++)
                {
                    if (ls.buy_amount[i] < vol)
                    {
                        vol -= ls.buy_amount[i];
                        count += 1;
                        amount += ls.buy_amount[i] * ls.buy_px[i];
                        quotePos += 1;
                    }
                    else
                    {
                        count += 1;
                        amount += vol * ls.buy_px[i];
                        vol = 0;
                        quotePos += 1;
                        break;
                    }
                }
            }

            Deal dl = new Deal();
            dl.code = od.code;
            dl.count = count;
            dl.time = GetCurrentTime();
            dl.id = od.id;
            dl.volume = od.volume - vol; //成交量
            if(dl.volume > 0)
            {
                dl.price = (float)amount / dl.volume;
            }
            dl.quotePos = quotePos;
            dl.side = od.side;
            if(vol == 0) //全部成交
            {
                orderDict.Remove(od.id);
            }
            else
            {
                od.volume = vol; //还有剩余，更新订单信息
            }
            return dl;
        }

        public Deal LimitOrderTransaction(Order od)
        {
            Level2Struct ls = SimulateMarket.GetInstance().GetMarketSnapshot(od.code);
            int vol = od.volume;
            int count = 0;
            double amount = 0;
            int quotePos = 0;

            if (od.side == TradeSide.Buy)
            {
                for (int i = 0; i < ls.sell_amount.Count; i++)
                {
                    if(od.price < ls.sell_px[i])
                    {
                        break; //第一档都买不进，就不用该考虑更高的档位了
                    }

                    if (ls.sell_amount[i] < vol)
                    {
                        vol -= ls.sell_amount[i];
                        count += 1;
                        amount += ls.sell_amount[i] * ls.sell_px[i];
                    }
                    else
                    {
                        count += 1;
                        amount += vol * ls.sell_px[i];
                        vol = 0;
                        break;
                    }
                }
            }
            else
            {
                for (int i = 0; i < ls.buy_amount.Count; i++)
                {
                    if(od.price > ls.buy_px[i])
                    {
                        break;
                    }
                    if (ls.buy_amount[i] < vol)
                    {
                        vol -= ls.buy_amount[i];
                        count += 1;
                        amount += ls.buy_amount[i] * ls.buy_px[i];
                        quotePos += 1;
                    }
                    else
                    {
                        count += 1;
                        amount += vol * ls.buy_px[i];
                        vol = 0;
                        quotePos += 1;
                        break;
                    }
                }
            }

            Deal dl = new Deal();
            dl.code = od.code;
            dl.count = count;
            dl.time = GetCurrentTime();
            dl.id = od.id;
            dl.volume = od.volume - vol; // 成交量
            if (dl.volume > 0)
            {
                dl.price = (float)amount / dl.volume;
            }
            dl.quotePos = quotePos;
            dl.side = od.side;
            if (vol == 0) //全部成交
            {
                
                orderDict.Remove(od.id); //全部成交，该订单就结束
            }
            else
            {
                od.volume = vol; // 还有剩余，更新该订单
            }
            return dl;
        }


        public void TimeSync() // 订单返回的时间需要与行情时间同步
        {

        }

        public DateTime LagTime(DateTime dt, int millisecond)
        {
            DateTime dt_later = dt + new TimeSpan(0, 0, 0, 0, millisecond);
            return dt_later;
        }

        public void AddOrder(Order od)  //由策略调用, 将指令塞入订单队列
        {
            orderQueue.Add(od);
        }

        public Order GetOrder() // 由交易所调用，获取队列中的订单
        {
            Order od = orderQueue.Take();
            return od;
        }


        public void Run()
        {
            while (true)
            {
                Order od = GetOrder();
                Transaction(od);

            }
        }
    }



    public class Order
    {
        public string id;
        public string targetId; // 撤销单对应的目标订单id
        public OrderType type;
        public string code;
        public float price; // 目标价格
        public TradeSide side; // 买，卖
        public int volume; // 目标量
        public Order()
        {
            ;
        }
    }

    public class Deal
    {
        public string id; //成交订单编号，暂时设为与接收的order单编号一致。
        public string code;
        public float price; //成交均价
        public DateTime time; //最终成交时间
        public int count; //成交笔数,分几笔成交的
        public int volume; //成交量
        public OrderType type; 
        public TradeSide side;
        public bool isCanceled; // 如果是撤销单，反馈是否撤销成功
        public int quotePos = 0; //如果遇到吃lv2情况，吃到lv2多少档
        public Deal()
        {
            price = 0;
            volume = 0;
        }
    }

    public enum OrderType
    {
        Market = 0,
        Limit = 1,
        Cancel = 2 //撤销单
    }


    public enum TradeSide
    {
        Buy = 0,
        Sell = 1,
    }

    public enum OrderState
    {
        Fill = 0,
        NotFill = 1,
        PartFill = 2,
        Cancel =3,
        PartCancel = 4,
        Send = 5, //已发
        NotSend = 6 //未发
    }
}
